#include "asan_signal_handler.h"
#include "asan_internal_defs.h"
#include "asan_internal.h"
#include "asan_interceptors.h"
#include <signal.h>
#include <ucontext.h>
#include "asan_report.h"

namespace __sanitizer {

SignalContext::SignalContext(siginfo_t* siginfo, ucontext_t* context)
    : siginfo(siginfo), context(context) {
  const siginfo_t* si = static_cast<const siginfo_t *>(siginfo);
  addr = (uptr)(si->si_addr);
  is_memory_access = si->si_signo == SIGSEGV || si->si_signo == SIGBUS;
  
  // uptr err = context->uc_mcontext.gregs[REG_ERR];
  // write_flag = err & PF_WRITE ? Write : Read;
  if (si->si_code == SEGV_ACCERR) {
    write_flag = Write;
  }
  else if (si->si_code == SEGV_MAPERR) {
    write_flag = Unknown;
  }
  is_true_faulting_addr = si->si_signo == SIGSEGV && si->si_code != 128;
}

void DeadlySignalHandler(int signal, siginfo_t* info, void* context) {
  VReport(ASAN_LOG_DEBUG, "%s:%d %s\n", __FILE__, __LINE__, __func__);
  SignalContext sc((siginfo_t*)info, (ucontext_t*)context);
  GET_CALLER_PC_BP_SP;
  ReportCapturedDeadlySignal(signal, pc, bp, sp, sc);
  Die();
}

void InstallDeadlySignalHandler(SignalHandlerFunc handler) {
  
  stack_t ss;
  ss.ss_sp = REAL(malloc(SIGSTKSZ));
  ss.ss_size = SIGSTKSZ;
  ss.ss_flags = 0;
  sigaltstack(&ss, NULL);

  struct sigaction action;
  action.sa_sigaction = handler;
  sigemptyset(&action.sa_mask);
  action.sa_flags = SA_SIGINFO | SA_ONSTACK;
  sigaction(SIGSEGV, &action, NULL);
  sigaction(SIGABRT, &action, NULL);
  sigaction(SIGBUS, &action, NULL);
  sigaction(SIGTRAP, &action, NULL);
  sigaction(SIGFPE, &action, NULL);
  sigaction(SIGILL, &action, NULL);
}

} // namespace __sanitizer
